package com.shixihub.browservice;

import com.ruiyun.jvppeteer.core.Puppeteer;
import com.ruiyun.jvppeteer.core.browser.Browser;
import com.ruiyun.jvppeteer.core.browser.BrowserFetcher;
import com.ruiyun.jvppeteer.core.page.Page;
import com.ruiyun.jvppeteer.options.LaunchOptions;
import com.ruiyun.jvppeteer.options.LaunchOptionsBuilder;
import com.ruiyun.jvppeteer.options.PDFOptions;
import com.ruiyun.jvppeteer.options.ScreenshotOptions;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.ExecutionException;

/**
 * @author LiShixi 2021/4/15 12:54 上午
 */
@Slf4j
public class JvppeteerService {
    /**
     * 环境变量PUPPETEER_EXECUTABLE_PATH设置chrome路径
     *  final String puppeteer_executable_path ="/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge" ;
     * @return
     */
    public Optional<Browser> getBrowser() {
        return getBrowser(System.getenv("PUPPETEER_EXECUTABLE_PATH"));
    }

    Browser browser = getBrowser().get();

    Optional<Browser> getBrowser(String exePath) {
        try {
            BrowserFetcher.downloadIfNotExist(null);
            ArrayList<String> arrayList = new ArrayList<>();
            LaunchOptions options = new LaunchOptionsBuilder()
                    .withExecutablePath(exePath)
                    .withArgs(arrayList)
                    .withHeadless(true)
                    .build();
            arrayList.add("--no-sandbox");
            arrayList.add("--disable-setuid-sandbox");

            return Optional.of( Puppeteer.launch(options));
        } catch (InterruptedException | ExecutionException | IOException e) {
            e.printStackTrace();
        }

        return Optional.empty();
    }

    Map<String, Page> pageCache = new HashMap<>();

    public String screenshot(String uri) throws InterruptedException, IOException, ExecutionException {
        System.out.println("screenshot url = " + uri);
        Page page;
        String url = (!uri.startsWith("http") ? "file://" : "") + uri;
        if (pageCache.containsKey(url)) {
            page = pageCache.get(url);
        } else {
            page = browser.newPage();
            pageCache.putIfAbsent(url, page);
        }
        page.setUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36 Edg/88.0.705.56");
        page.goTo(url);

        ScreenshotOptions screenshotOptions = new ScreenshotOptions();
        //设置截图范围
        screenshotOptions.setType("png");
        screenshotOptions.setFullPage(true);
        //page.close();
        //browser.close();
        return page.screenshot(screenshotOptions);
    }

    public Optional<String> echartsConvert(String option, String pageFunction,String domId) {
        return echartsConvert(ECHART_DOM, option, pageFunction,domId);
    }

    public Optional<String> echartsConvert(String html, String option, String pageFunction,String domId) {
        final Optional<Browser> browser1 = getBrowser();
        if (browser1.isPresent()) {
            final Page page = browser.newPage();
            page.setJavaScriptEnabled(true);
            page.setCacheEnabled(false);
            page.onError(event -> {
                log.error(event.getMessage());
            });
            String seed = html;
            if(Strings.isBlank(domId)){
                domId ="canvas";
            }

            //关闭动画
            if (Strings.isNotBlank(option)) {
                String optionStr = "<script type=\"text/javascript\">(function (window) {\n" +
                        "var echarts = window.echarts.init(document.getElementById('"+domId+"'));" +
                        "echarts.setOption(Object.assign(" + option + ",{animation: false}));\n" +
                        "})(this);</script>";
                seed = seed.replace("${optionOrFunction}", optionStr)
                .replace("${domId}", domId);
            } else if (Strings.isNotBlank(pageFunction)) {
                String optionStr = "<script type=\"text/javascript\">" +
                        pageFunction.replace(".setOption(option)",".setOption(Object.assign(option,{animation:false}))") +
                        "option && echarts && echarts.setOption(Object.assign(option,{animation:false}));"+
                        "</script>";
                seed = seed.replace("${optionOrFunction}", optionStr)
                        .replace("${domId}", domId);
            }
            page.setContent(seed);

            try {
                // 调试用
                //Files.write(Paths.get("test-echarts-out.html"), page.content().getBytes(StandardCharsets.UTF_8));

                final ScreenshotOptions screenshotOptions = new ScreenshotOptions();
                screenshotOptions.setType("png");
                return Optional.ofNullable(page.$("#canvas")
                        .screenshot(screenshotOptions));
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    page.close();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        return Optional.empty();
    }

    final static String ECHART_DOM = getSeedHtml();

    public static String getSeedHtml() {
        try {
            final String path = BrowServiceController.class.getClassLoader().getResource("js/seed.html").getPath();
            final List<String> strings = Files.readAllLines(Paths.get(path));
            return Strings.join(strings, '\n');
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ECHART_DOM;
    }

    public void pdf(String url) {
        try {
            //自动下载，第一次下载后不会再下载
            BrowserFetcher.downloadIfNotExist(null);
            ArrayList<String> arrayList = new ArrayList<>();
            //生成pdf必须在无厘头模式下才能生效
            LaunchOptions options = new LaunchOptionsBuilder().withArgs(arrayList).withHeadless(true).build();
            arrayList.add("--no-sandbox");
            arrayList.add("--disable-setuid-sandbox");
            Browser browser = Puppeteer.launch(options);
            Page page = browser.newPage();
            page.goTo(url);
            PDFOptions pdfOptions = new PDFOptions();
            pdfOptions.setPath("test.pdf");
            page.pdf(pdfOptions);
            page.close();
            browser.close();
        } catch (InterruptedException | IOException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}
